import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { FastifyRequest } from 'fastify';

import { BusinessException } from '~/common/exceptions/biz.exception';
import { ErrorEnum } from '~/constants/error-code.constant';
// import { AuthService } from '~/modules/auth/auth.service';

import { ALLOW_ANON_KEY, PERMISSION_KEY, PUBLIC_KEY } from '../auth.constant';
import { AuthService } from '../auth.service';

@Injectable()
export class RbacGuard implements CanActivate {
  constructor(
    private reflector: Reflector,
    private authService: AuthService
  ) {}

  async canActivate(context: ExecutionContext) {
    const isPublic = this.reflector.getAllAndOverride<boolean>(PUBLIC_KEY, [
      context.getHandler(),
      context.getClass()
    ]);

    if (isPublic) return true;

    const request = context.switchToHttp().getRequest<FastifyRequest>();
    const { user } = request;
    if (!user) throw new BusinessException(ErrorEnum.INVALID_LOGIN);

    // allowAnon 是需要登录后可访问(无需权限), Public 则是无需登录也可访问.
    const allowAnon = this.reflector.get<boolean>(ALLOW_ANON_KEY, context.getHandler());
    if (allowAnon) return true;
    const payloadPermission = this.reflector.getAllAndOverride<string | string[]>(PERMISSION_KEY, [
      context.getHandler(),
      context.getClass()
    ]);
    console.log(user, 'user');
    console.log(payloadPermission, 'payloadPermission');
    const allPermissions = await this.authService.getPermissions(user.uid);
    let canNext = false;

    // handle permission strings
    if (Array.isArray(payloadPermission)) {
      // 只要有一个权限满足即可
      canNext = payloadPermission.every((i) => allPermissions.includes(i));
    }

    if (typeof payloadPermission === 'string') canNext = allPermissions.includes(payloadPermission);

    if (!canNext) throw new BusinessException(ErrorEnum.NO_PERMISSION);
    return true;
  }
}
